﻿using StarUtils.Extension;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace StarUtils.Http
{
    public interface IHttpRequest : IRequest<IHttpRequest>
    {
        IHttpRequest OnSuccess(Action<string> action);

        IHttpRequest OnSuccess(Action<string, HttpStatusCode> action);

        Task<TResult> ResultFromJsonAsync<TResult>();

        new Task<Stream> ResultStream();

        new Task<byte[]> ResultBytes();
    }
    public class HttpRequest : HttpRequestBase<IHttpRequest>, IHttpRequest, IRequest<IHttpRequest>
    {
        private Action<string> _successAction;

        private Action<string, HttpStatusCode> _successStatusCodeAction;

        public HttpRequest(HttpMethod httpMethod, string url, HttpClient client)
            : base(httpMethod, url, client)
        {
        }

        public IHttpRequest OnSuccess(Action<string> action)
        {
            _successAction = action;
            return this;
        }

        public IHttpRequest OnSuccess(Action<string, HttpStatusCode> action)
        {
            _successStatusCodeAction = action;
            return this;
        }

        protected override void SuccessHandler(string result, HttpStatusCode statusCode, string contentType)
        {
            _successAction?.Invoke(result);
            _successStatusCodeAction?.Invoke(result, statusCode);
        }

        public async Task<TResult> ResultFromJsonAsync<TResult>()
        {
            return JsonHelper.ToObject<TResult>(await ResultAsync());
        }
    }

    public interface IHttpRequest<TResult> : IRequest<IHttpRequest<TResult>> where TResult : class
    {
        IHttpRequest<TResult> OnSuccess(Action<TResult> action, Func<string, TResult> convertAction = null);

        IHttpRequest<TResult> OnSuccess(Action<TResult, HttpStatusCode> action, Func<string, TResult> convertAction = null);

        Task<TResult> ResultFromJsonAsync();

        new Task<Stream> ResultStream();

        new Task<byte[]> ResultBytes();
    }

    public class HttpRequest<TResult> : HttpRequestBase<IHttpRequest<TResult>>, IHttpRequest<TResult>, IRequest<IHttpRequest<TResult>> where TResult : class
    {
        private Action<TResult> _successAction;

        private Action<TResult, HttpStatusCode> _successStatusCodeAction;

        private Func<string, TResult> _convertAction;

        public HttpRequest(HttpMethod httpMethod, string url, HttpClient client)
            : base(httpMethod, url, client)
        {
        }

        public IHttpRequest<TResult> OnSuccess(Action<TResult> action, Func<string, TResult> convertAction = null)
        {
            _successAction = action;
            _convertAction = convertAction;
            return this;
        }

        public IHttpRequest<TResult> OnSuccess(Action<TResult, HttpStatusCode> action, Func<string, TResult> convertAction = null)
        {
            _successStatusCodeAction = action;
            _convertAction = convertAction;
            return this;
        }

        protected override void SuccessHandler(string result, HttpStatusCode statusCode, string contentType)
        {
            TResult val = ConvertTo(result, contentType);
            _successAction?.Invoke(val);
            _successStatusCodeAction?.Invoke(val, statusCode);
        }

        private TResult ConvertTo(string result, string contentType)
        {
            if (typeof(TResult) == typeof(string))
            {
                return Conv.To<TResult>(result);
            }

            if (_convertAction != null)
            {
                return _convertAction(result);
            }

            if (contentType.SafeString().ToLower() == "application/json")
            {
                return JsonHelper.ToObject<TResult>(result);
            }

            return null;
        }

        public async Task<TResult> ResultFromJsonAsync()
        {
            return JsonHelper.ToObject<TResult>(await ResultAsync());
        }
    }

}
